package com.lib.net;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.lib.net.util.LogUtils;
import com.lib.net.util.SharedPreferenceUtils;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.logging.HttpLoggingInterceptor;

/**
 * Created by Joey on 2018/3/27.
 *
 * @author Joey
 */

public class NetClient {

    private static OkHttpClient client;
    /**
     * 打印请求参数
     */
    private static HttpLoggingInterceptor loggingInterceptor;
    /**
     * 自定义公共补充body内容
     */
    private static Map<String, String> extraParams = new HashMap<>();
    /**
     * 自定义公共补充header内容
     */
    private static Map<String, String> extraHeader = new HashMap<>();
    /**
     * 自定义公共补充入参内容
     */
    private static Map<String, String> extra = new HashMap<>();

    /**
     * 自定义公共补充入参标识
     */
    private static String extraKey;

    /**
     * 请求标记
     */
    private String tag;

    public NetClient() {
        this("default");
    }

    public NetClient(String tag) {
        this.tag = tag;
    }


    public static void addParams(String key, String value) {
        extraParams.put(key, value);
        SharedPreferenceUtils.getInstance().putString(key, value);
    }

    public static void addExtra(String key, String value) {
        extra.put(key, value);
        SharedPreferenceUtils.getInstance().putString(key, value);
    }

    public static void addExtraHeader(String key, String value) {
        extraHeader.put(key, value);
        SharedPreferenceUtils.getInstance().putString(key, value);
    }

    public static void clearExtraHeaders() {
        if (extraHeader.isEmpty()) {
            return;
        }
        for (String key : extraHeader.keySet()) {
            SharedPreferenceUtils.getInstance().remove(key);
        }
        extraHeader.clear();
    }

    public static void clearExtra() {
        if (extra.isEmpty()) {
            return;
        }
        for (String key : extra.keySet()) {
            SharedPreferenceUtils.getInstance().remove(key);
        }
        extra.clear();
    }

    public static void clearExtraParams() {
        if (extraParams.isEmpty()) {
            return;
        }
        for (String key : extraParams.keySet()) {
            SharedPreferenceUtils.getInstance().remove(key);
        }
        extraParams.clear();
    }

    public void uploads(String url, Map<String, String> mapParams, NetResponseListener responseListener, File... files) {
        FileProperty property = new FileProperty(files);
        uploadLots(url, mapParams, responseListener, property);
    }

    public void uploadLots(String url, Map<String, String> mapParams, NetResponseListener responseListener, FileProperty... fileProperties) {
        excute(createRequest(url, createMultipartBody(mapParams, responseListener, fileProperties)), responseListener);
    }

    public void uploadLots(String url, String methodName, Map<String, String> mapParams, NetResponseListener responseListener, FileProperty... fileProperties) {
        uploadLots(url + methodName, mapParams, responseListener, fileProperties);
    }

    public void uploads(String url, String methodName, Map<String, String> mapParams, NetResponseListener responseListener, File... files) {
        uploads(url + methodName, mapParams, responseListener, files);
    }

    public void httpPost(String url, Map<String, String> mapParams, NetResponseListener responseListener) {
        excute(createRequest(url, createFormBody(mapParams)),
                responseListener);
    }

    public <T> void httpJsonPost(String url, T params, NetResponseListener responseListener) {
        excute(createRequest(url, createJsonBody(params)),
                responseListener);
    }

    public <T> void httpJsonPost(String url, String methodName, T mapParams, NetResponseListener responseListener) {
        excute(createRequest(url + methodName, createJsonBody(mapParams)), responseListener);
    }

    public void httpPost(String url, String methodName, Map<String, String> mapParams, NetResponseListener responseListener) {
        excute(createRequest(url + methodName, createFormBody(mapParams)),
                responseListener);
    }


    public void httpGet(String url, NetResponseListener responseListener) {
        excute(createRequest(url), responseListener);
    }

    public void httpGet(String url, String methodName, NetResponseListener responseListener) {
        httpGet(url + methodName, responseListener);
    }

    public void download(String url, NetResponseListener responseListener) {
        excute(createRequest(url, null), responseListener);
    }

    public void download(String url, String methodName, NetResponseListener responseListener) {
        excute(createRequest(url + methodName, null), responseListener);
    }

    protected Request createRequest(String url, RequestBody body) {
        url = getUrl(url).toString();
        final Request.Builder builder = new Request.Builder();
        builder.url(url)
                .tag(tag);
        // 添加补充头部数据，用于一些用户验证或者鉴权的内容
        if (null != extraHeader && !extraHeader.isEmpty()) {
            for (String key : extraHeader.keySet()) {
                builder.addHeader(key, extraHeader.get(key));
            }
        }
        builder.post(body);
        return builder.build();
    }

    private HttpUrl getUrl(String url) {
        HttpUrl.Builder urlBuilder = HttpUrl.parse(url)
                .newBuilder();

        // 添加补充Params数据
        if (null != extraParams && !extraParams.isEmpty()) {
            for (String key : extraParams.keySet()) {
                urlBuilder.addQueryParameter(key, extraParams.get(key));
            }
        }
        LogUtils.i("url = " + urlBuilder.build());
        return urlBuilder.build();
    }

    protected Request createRequest(String url) {
        url = getUrl(url).toString();
        LogUtils.i("url = " + url);
        final Request.Builder builder = new Request.Builder();
        builder.url(url)
                .tag(tag);
        // 添加补充头部数据，用于一些用户验证或者鉴权的内容
        if (null != extraHeader && !extraHeader.isEmpty()) {
            for (String key : extraHeader.keySet()) {
                builder.addHeader(key, extraHeader.get(key));
            }
        }
        builder.get();
        return builder.build();
    }


    protected FormBody createFormBody(Map<String, String> params) {
        FormBody.Builder formBody = new FormBody.Builder();
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                formBody.add(key, params.get(key));
            }
            LogUtils.i("map = " + params.toString());
        }
        return formBody.build();
    }

    protected <T> RequestBody createJsonBody(T t) {
        if (t instanceof Map) {
            if (null == getExtraKey() || getExtraKey().isEmpty()) {
                // 添加补充extra数据
                if (null != extra && !extra.isEmpty()) {
                    ((Map) t).putAll(extra);
                }
            } else {
                Object object = ((Map) t).get(extraKey);

                if (null != object) {
                    if (object instanceof String) {
                        JsonObject jsonObject = null;
                        for (String key : extra.keySet()) {
                            jsonObject = new Gson().fromJson(object.toString(), JsonObject.class);
                            jsonObject.addProperty(key, extra.get(key));
                        }
                        ((Map) t).put(extraKey, new Gson().toJson(jsonObject));
                    }
                    if (object instanceof JsonObject) {
                        for (String key : extra.keySet()) {
                            ((JsonObject) object).addProperty(key, extra.get(key));
                        }
                        ((Map) t).put(extraKey, object);
                    }
                }
            }
        }
        String params = new Gson().toJson(t);
        MediaType JSON = MediaType.parse("application/json; charset=utf-8");
        LogUtils.i(" json = " + params);
        RequestBody body = RequestBody.create(JSON, params);
        return body;
    }

    /**
     * @param params
     * @param listener
     * @param properties
     * @return
     */
    protected MultipartBody createMultipartBody(Map<String, String> params, OnUploadListener listener, FileProperty... properties) {
        MultipartBody.Builder builder = new MultipartBody.Builder();
        builder.setType(MultipartBody.FORM);
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                builder.addFormDataPart(key, params.get(key));
            }
            LogUtils.i("map = " + params.toString());
        }

        if (properties == null || properties.length == 0) {
            return builder.build();
        }
        for (FileProperty property : properties) {
            int i = 0;
            File[] files = property.getFiles();
            if (files != null && files.length > 0) {
                for (File f : files) {
                    RequestBody body = UploadRequestBody.createCustomRequestBody(MultipartBody.FORM, i, listener, f);
                    builder.addFormDataPart(property.getKey(), f.getName(), body);
                    i++;
                }
            }
        }

        return builder.build();

    }

    /**
     * @param request
     * @param responseListener
     */
    private void excute(Request request, NetResponseListener responseListener) {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(NetClientConfig.I.getTimeout(), TimeUnit.MILLISECONDS);
        builder.readTimeout(NetClientConfig.I.getTimeout() * 2, TimeUnit.MILLISECONDS);
        builder.writeTimeout(NetClientConfig.I.getTimeout() * 2, TimeUnit.MILLISECONDS);
        if (client == null) {
            loggingInterceptor = new HttpLoggingInterceptor(new HttpLogger());
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            client = builder.addNetworkInterceptor(loggingInterceptor).build();
        }
        client.newCall(request).enqueue(responseListener);
        responseListener.onStart();
    }

    /**
     * 取消队列中标记的请求
     *
     * @param tag
     */
    public static void cancel(String tag) {
        if (tag == null || client == null) {
            return;
        }
        for (Call call : client.dispatcher().queuedCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
        for (Call call : client.dispatcher().runningCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }

    }

    /**
     * 取消队列中的所有请求
     */
    public static void cacelAll() {
        if (client == null) {
            return;
        }
        for (Call call : client.dispatcher().queuedCalls()) {
            call.cancel();
        }
        for (Call call : client.dispatcher().runningCalls()) {
            call.cancel();
        }
    }

    public static String getExtraKey() {
        return extraKey;
    }

    public static void setExtraKey(String extraKey) {
        NetClient.extraKey = extraKey;
    }

    private String getParams(String key) {
        String value;
        if (extraParams.isEmpty()) {
            value = SharedPreferenceUtils.getInstance().getString(key);
        } else {
            value = extraParams.get(key);
        }
        return value;
    }

}
